#include "../header.h"
//udp接收端编程。只接收数据。但是也可增加发送功能。
//1 socket : 建立数据报套接字
//2.bind 绑定  绑定自己的IP PORT  sid
//3.接收数据， recvfrom
//4.关闭套接字。
/**
 * @函数原型: ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
 *              struct sockaddr *src_addr, socklen_t *addrlen);
 * @函数功能: receive a message from a socket  从套接字文件中。接收数据。
 * @参数说明: 
 * @       参数1: sockfd  套接字
 * @       参数2: buf 接收数据缓冲区的起始位置。
 * @       参数3: len ：缓冲区长度。
 *  @       参数4: flags ： 0 。
 *  @       参数5: struct sockaddr *src_addr ： 地质结构体，存储对方的信息，对方是发送端。
 *  @       参数6: addrlen ： 地址长度的地址。
 * @返回值: These calls return the number of bytes received, or -1 if an error occurred.
 * 实际读到的字节个数。
 * @param {int} argc
 */
int main(int argc, char const *argv[])
{
    //从命令行把ip port传递进来。
    if(argc < 3)
    {
        perror("命令行正确参数:./a.out ip port\n");
        return -1;
    }

    int sid = socket(AF_INET,SOCK_DGRAM,0);
    printf("sid = %d\n",sid);

    //2 bind
    struct sockaddr_in saddr = {0};
    saddr.sin_addr.s_addr = inet_addr(argv[1]);
    saddr.sin_port = htons(atoi(argv[2]));
    saddr.sin_family = AF_INET;
    int res = bind(sid,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res < 0)
    {
        perror("绑定失败!\n");
        return -2;
    }
    printf("绑定成功!\n");

    //3.接收数据信息。
    //caddr： 存储对方的地址信息。
    struct sockaddr_in caddr = {0};
    char bufs[128] = "";
    int size = sizeof(caddr);
    //recv read recvfrom 都是阻塞属性
    //循环接收数据。
    int len = 0 ;
    char ipk[16] = "";
    while(1)
    {
        bzero(bufs,sizeof(bufs));
        bzero(ipk,sizeof(ipk));//清空数组
        len = recvfrom(sid,bufs,sizeof(bufs),0,(struct sockaddr*)&caddr,&size);
        printf("发送端的ip是:%s\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ipk,sizeof(ipk)));
        printf("发送端的端口号是:%d\n",ntohs(caddr.sin_port));
        printf("发送端的信息是:%s 数据长度是:%d\n",bufs,len);
        // if(!strncmp(bufs,"quit",4))  
        // {
        //     printf("接收端正在退出...\n");
        //     break;
        // }
    }
    //关闭套接字
    close(sid);


    return 0;
}
